package com.hellloop.pim.alphabeat.network;

import java.io.IOException;
import java.net.*;
import java.util.*;


class PIMServerConnectionThread extends Thread {

	private PIMServerMessageProcessor processor;
	
	private ServerSocket servSock;

	private PIMServer server;

	private Vector<PIMClientHandler> clientHandlerList;
	
	private int clientId = 1;

	// --------------------- Connection methods ------------------------

	PIMServerConnectionThread(PIMServer pimServer, int port, PIMServerMessageProcessor processor) throws IOException {
		this.server = pimServer;
		servSock = new ServerSocket(port);
		clientHandlerList = new Vector<PIMClientHandler>();
		this.processor = processor;
	}

	void openConnection() {
		this.start();
	}

	public void run() {

		while (true) {
			try {
				Socket clientSocket;

				while (true) {
					clientSocket = servSock.accept();
					System.out.println("ACCEPT!!");
					System.out.println("Server:" + clientSocket);

					try {
						PIMClientHandler clientHandler = new PIMClientHandler(
								this, this.getNewClientId(), clientSocket, processor);
						clientHandlerList.add(clientHandler);
					} catch (IOException e1) {
						// We can do nothing if cannot instantiate the
						// InputStream
						// and the OutputStream for that Socket
						// Client has to wait for the connection timeout
						e1.printStackTrace();
					}

				}

			} catch (IOException e) {
				// Exception while doing servSock.accept()
				e.printStackTrace();
			}

		}

	}

	void closeConnection() throws IOException {
		// TODO Send close connection message to every Sockets
		if (servSock != null) {
			servSock.close();
		}
	}

	// ----------------- Message Handling Methods ------------------

	void sendMessageToAllClients(PIMMessage msg) {
		for (PIMClientHandler clientHandler : clientHandlerList) {
			clientHandler.sendMessage(msg);
		}
	}
	
	void sendMessageToAllClientsExceptOne(PIMMessage msg, int id){
		for (PIMClientHandler clientHandler : clientHandlerList) {
			if(clientHandler.getClientId() != id)
				clientHandler.sendMessage(msg);
		}
	}
	
	void sendMessageToOneClient(PIMMessage msg, int id){
		for (PIMClientHandler clientHandler : clientHandlerList) {
			if(clientHandler.getClientId() == id) {
				clientHandler.sendMessage(msg);
				break;
			}
		}
	}
	
	void sendMessageToClients(PIMMessage msg, Collection<Integer> clientList){
		
		Set<Integer> clientSet;
		if(clientList instanceof Set){
			clientSet = (Set<Integer>) clientList;
		} else {
			clientSet = new HashSet<Integer>();
			clientSet.addAll(clientList);
		}
		
		for (PIMClientHandler clientHandler : clientHandlerList) {
			if(clientSet.contains(new Integer(clientHandler.getClientId()))) {
				clientHandler.sendMessage(msg);
			}
		}
	}

	int getClientCount() {
		return clientHandlerList.size();
	}

	String[] getClientList() {
		ArrayList<String> clientList = new ArrayList<String>();
		for (PIMClientHandler client : clientHandlerList) {
			clientList.add(client.toString());
		}
		return clientList.toArray(new String[0]);
	}
	
	/**
	 * In fact, this method may not have to be synchronized
	 * @return
	 */
	private synchronized int getNewClientId(){
		return clientId++;
	}

}
